<template>
    <div id="app">
        <div class="container">
            <!-- 创建一个canvas画布 npmn-js是通过canvas实现绘图的，并设置ref让vue获取到element -->
            <div class="bpmn-canvas" ref="canvas"></div>
            <!-- 工具栏显示的地方 -->
            <div class="bpmn-js-properties-panel" id="js-properties-panel">
                <div v-show="nodeStatus" class="rightMenu">
                    <el-form ref="form" :model="form" label-width="100px">
                        <el-form-item label="节点名称">
                            <el-input v-model="form.name" palceholder="请输入节点名称"
                                @change="(event) => changeField(event, 'name')"></el-input>
                        </el-form-item>
                        <el-form-item label="选择表单">
                            <el-select v-model="form.region" placeholder="请选择表单">
                                <el-option label="区域一" value="shanghai"></el-option>
                                <el-option label="区域二" value="beijing"></el-option>
                            </el-select>
                        </el-form-item>
                        <el-form-item label="节点版本">
                            <el-input v-model="form.bide" palceholder="请输入节点版本"></el-input>
                        </el-form-item>
                        <el-form-item label="节点权限">
                            <el-button type="primary" size="small">查看/设置</el-button>
                        </el-form-item>
                        <el-form-item label="审批设置">
                            <el-checkbox-group v-model="form.type">
                                <el-checkbox label="转交" name="type"></el-checkbox>
                                <el-checkbox label="加签" name="type1"></el-checkbox>
                                <el-checkbox label="驳回" name="type2"></el-checkbox>
                                <el-checkbox label="待定" name="type3"></el-checkbox>
                                <el-checkbox label="拒绝" name="type4"></el-checkbox>
                                <el-checkbox label="建议拒绝" name="type5"></el-checkbox>
                            </el-checkbox-group>
                        </el-form-item>
                        <el-form-item label="驳回节点">
                            <el-select v-model="form.region" placeholder="请选择驳回节点">
                                <el-option label="区域一" value="shanghai"></el-option>
                                <el-option label="区域二" value="beijing"></el-option>
                            </el-select>
                        </el-form-item>
                        <el-form-item label="是否抄送">
                            <el-radio-group v-model="form.resource">
                                <el-radio label="是"></el-radio>
                                <el-radio label="否"></el-radio>
                            </el-radio-group>
                        </el-form-item>
                        <el-form-item label="抄送用户">
                            <el-select v-model="form.region" multiple placeholder="请选择抄送用户">
                                <el-option label="区域一" value="shanghai"></el-option>
                                <el-option label="区域二" value="beijing"></el-option>
                            </el-select>
                        </el-form-item><el-form-item multiple label="审批角色">
                            <el-select v-model="form.regionw" placeholder="请选择审批角色">
                                <el-option label="区域一" value="shanghai"></el-option>
                                <el-option label="区域二" value="beijing"></el-option>
                            </el-select>
                        </el-form-item>
                        <el-form-item label="指定审批人员">
                            <el-radio-group v-model="form.resource3">
                                <el-radio label="是"></el-radio>
                                <el-radio label="否"></el-radio>
                            </el-radio-group>
                        </el-form-item>
                        <el-form-item label="审批用户">
                            <el-select v-model="form.region" multiple placeholder="请选择审批用户">
                                <el-option label="区域一" value="shanghai"></el-option>
                                <el-option label="区域二" value="beijing"></el-option>
                            </el-select>
                        </el-form-item><el-form-item label="可拒绝用户">
                            <el-select v-model="form.regionw" multiple placeholder="请选择可拒绝用户">
                                <el-option label="区域一" value="shanghai"></el-option>
                                <el-option label="区域二" value="beijing"></el-option>
                            </el-select>
                        </el-form-item>
                    </el-form>

                </div>
                <div v-show="conditionStatus">
                    <div>
                        <div style="margin:10px 5px"><span>节点名称</span><span>{{ }}</span></div>
                        <div v-for="(val, index) in formData" :key="index">
                            <el-card>
                                <div>{{ val.title }}{{ index + 1 }}</div>
                                <div v-for="(item, index) in val.data" :key="index">
                                    <div style="display: flex;">
                                        <el-select v-model="item.type" placeholder="请选择"
                                            @change="(e) => firstChange(e, item, val)">
                                            <el-option v-for="res in typeOptions" :key="res.value" :label="res.label"
                                                :value="res.value">
                                            </el-option>
                                        </el-select>
                                        <el-select v-model="item.type" placeholder="请选择" v-if="item.state1"
                                            @change="(e) => secendChange(e, item, val)">
                                            <el-option v-for="res1 in typeOptions" :key="res1.value" :label="res1.label"
                                                :value="res1.value">
                                            </el-option>
                                        </el-select>
                                        <el-input v-model="item.input" placeholder="请输入内容" disabled
                                            v-if="!item.state1"></el-input>
                                        <el-select v-model="item.type" placeholder="请选择" v-if="item.state2"
                                            @change="(e) => seardChange(e, item, val)">
                                            <el-option v-for="res2 in typeOptions" :key="res2.value" :label="res2.label"
                                                :value="res2.value">
                                            </el-option>
                                        </el-select>
                                        <el-input v-model="item.inputValue" placeholder="请输入内容" disabled
                                            v-if="!item.state2"></el-input>
                                    </div>
                                    <div><el-tag v-if="val.data.length > 1">or</el-tag></div>
                                </div>
                                <div style="text-align: center;margin-top:10px"> <el-button type="primary"
                                        icon="el-icon-plus" @click="addField(val)">增加字段</el-button>
                                </div>
                            </el-card>
                            <el-tag type="warning" v-if="formData.length > 1">and</el-tag>
                        </div>
                        <div style="text-align: center;margin-top:10px"><el-button type="primary" icon="el-icon-plus"
                                @click="addCondition()">增加条件</el-button></div>

                    </div>
                </div>
            </div>


            <!-- 把操作按钮写在这里面 -->
            <div class="action">
                <el-tooltip effect="light" content="导入Bpmn" placement="top">
                    <el-upload action class="upload-demo" :before-upload="openBpmn">
                        <el-button icon="el-icon-folder-opened"></el-button>
                    </el-upload>
                </el-tooltip>
                <el-tooltip effect="light" content="新建流程" placement="top">
                    <el-button class="new" icon="el-icon-circle-plus" @click="newDiagram"></el-button>
                </el-tooltip>
                <el-tooltip effect="light" content="下载Bpmn" placement="top">
                    <el-button icon="el-icon-download" @click="downloadBpmn"></el-button>
                </el-tooltip>
                <el-tooltip effect="light" content="下载Svg" placement="top">
                    <el-button icon="el-icon-picture" @click="downloadSvg"></el-button>
                </el-tooltip>

                <el-button-group style="margin-left: 10px;">
                    <el-button @click="handlerUndo">撤销</el-button>
                    <el-button @click="handlerRedo">恢复</el-button>
                </el-button-group>
                <el-button-group style="margin-left: 10px;">
                    <el-button @click="handlerZoom(0.1)">放大</el-button>
                    <el-button @click="handlerZoom(-0.1)">缩小</el-button>
                    <el-button @click="handlerZoom(0)">还原</el-button>
                </el-button-group>
                <!-- <el-button-group style="margin-left: 10px;">
                    <el-button @click="perviewXML">xml预览</el-button>
                    <el-button @click="perviewSVG">svg预览</el-button>
                </el-button-group> -->
                <el-button-group style="margin-left: 10px;">
                    <el-button @click="save()">保存</el-button>
                </el-button-group>

                <!-- 预览弹出 -->
                <el-dialog title="XML预览" append-to-body width="80%" :visible.sync="perviewXMLShow">
                    <div style="max-height: 65vh;overflow: auto;">
                        <pre v-highlight="perviewXMLStr"><code></code></pre>
                    </div>
                </el-dialog>
                <el-dialog title="SVG预览" append-to-body width="80%" :visible.sync="perviewSVGShow">
                    <div style="text-align: center;" v-html="perviewSVGData" />
                </el-dialog>

                <!-- <a hidden ref="downloadLink"></a> -->
            </div>
        </div>
    </div>
</template>
  
<script>
// bpmn 相关依赖
// import 'bpmn-js/dist/assets/diagram-js.css'
// import 'bpmn-js/dist/assets/bpmn-font/css/bpmn.css'
// import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-codes.css'
// import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css'

// 左边工具栏以及编辑节点的样式
// import 'bpmn-js-properties-panel/dist/assets/bpmn-js-properties-panel.css'


// import BpmnModeler from "bpmn-js/lib/Modeler";
// 左边工具栏以及节点
// import propertiesProviderModule from "bpmn-js-properties-panel/lib/provider/camunda";
// 右边的工具栏
// import propertiesPanelModule from "bpmn-js-properties-panel";
// import camundaModdleDescriptor from "camunda-bpmn-moddle/resources/camunda";

// BPMN国际化
// import customTranslate from './customTranslate/customTranslate';
// 自定义汉化模块
var customTranslateModule = {
    translate: ['value', customTranslate]
};


export default {
    name: "Bpmn",
    props: {
        /* 编辑器的内容 */
        value: {
            type: String,
            default: "",
        },
        /* 只读 */
        readOnly: {
            type: Boolean,
            default: false,
        },
    },
    components: {

    },
    data() {
        return {
            form: {
                name: '',
                region: '',
                date1: '',
                date2: '',
                delivery: false,
                type: [],
                resource: '',
                desc: ''
            },
            nodeId: '',
            xmlData: '',
            nodeStatus: false,
            conditionStatus: false,
            element: {
                id: 1,
                name: '2'
            },
            eventTypesArr: [
                { value: '1', label: 2 },
                { value: '3', label: 4 },
            ],
            eventType: '1',
            bpmnModeler: null,
            scale: 1,
            canvas: null,
            bpmnTemplate: `
            <?xml version="1.0" encoding="UTF-8"?>
            <definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="sid-38422fae-e03e-43a3-bef4-bd33b32041b2" targetNamespace="http://bpmn.io/bpmn" exporter="bpmn-js (https://demo.bpmn.io)" exporterVersion="5.1.2">
            <process id="Process_1" isExecutable="false">
                <startEvent id="StartEvent_1y45yut" name="开始">
                <outgoing>SequenceFlow_0h21x7r</outgoing>
                </startEvent>
                <task id="Task_1hcentk">
                <incoming>SequenceFlow_0h21x7r</incoming>
                </task>
                <sequenceFlow id="SequenceFlow_0h21x7r" sourceRef="StartEvent_1y45yut" targetRef="Task_1hcentk" />
            </process>
            <bpmndi:BPMNDiagram id="BpmnDiagram_1">
                <bpmndi:BPMNPlane id="BpmnPlane_1" bpmnElement="Process_1">
                <bpmndi:BPMNShape id="StartEvent_1y45yut_di" bpmnElement="StartEvent_1y45yut">
                    <omgdc:Bounds x="152" y="102" width="36" height="36" />
                    <bpmndi:BPMNLabel>
                    <omgdc:Bounds x="160" y="145" width="22" height="14" />
                    </bpmndi:BPMNLabel>
                </bpmndi:BPMNShape>
                <bpmndi:BPMNShape id="Task_1hcentk_di" bpmnElement="Task_1hcentk">
                    <omgdc:Bounds x="240" y="80" width="100" height="80" />
                </bpmndi:BPMNShape>
                <bpmndi:BPMNEdge id="SequenceFlow_0h21x7r_di" bpmnElement="SequenceFlow_0h21x7r">
                    <omgdi:waypoint x="188" y="120" />
                    <omgdi:waypoint x="240" y="120" />
                </bpmndi:BPMNEdge>
                </bpmndi:BPMNPlane>
            </bpmndi:BPMNDiagram>
            </definitions>
        `,
            perviewXMLStr: null,
            perviewSVGData: null,
            perviewXMLShow: false,
            perviewSVGShow: false,
            formData: [{
                title: '条件', data: [
                    {
                        name: '条件',
                        type: '',
                        condition: '',
                        value: '',
                        input: '=',
                        inputValue: '',
                        state1: true,
                        state2: true,
                    }
                ]
            }],
            typeOptions: [],
        };
    },
    mounted() {
        this.init();
    },
    methods: {
        // 条件节点-第一个下拉框
        firstChange(value, info, data) {

        },
        // 条件节点-第二个下拉框
        secendChange(value, info, data) {

        },
        // 条件节点-第三个下拉框
        seardChange(value, info, data) {

        },
        // 添加字段
        addField(info) {
            this.formData.map((res) => {
                if (res.id == info.id) {
                    let obj = {
                        name: '条件',
                        id: res.data.length + 1,
                        type: '',
                        condition: '',
                        value: '',
                        input: '=',
                        inputValue: '',
                        state1: true,
                        state2: true,
                    }
                    res.data.push(obj)
                }
            })
            console.log(info, 2222222222)
        },
        // 添加条件
        addCondition() {
            let obj = {
                title: '条件', id: this.formData.length + 1, data: [
                    {
                        name: '条件',
                        id: 1,
                        type: '',
                        condition: '',
                        value: '',
                        input: '=',
                        inputValue: '',
                        state1: true,
                        state2: true,
                    }
                ]
            }
            this.formData.push(obj)
        },
        // 保存
        save() {
            console.log(this.xmlData)
        },
        changeField(e, info) {
            const modeling = this.bpmnModeler.get('modeling');
            if (JSON.stringify(this.nodeId) === '{}') {
                this.$message.info('请保证要更改的节点处于选中状态!');
                return false;
            } else {
                modeling.updateLabel(this.nodeId, e);
            }
            this.$set(this.element, 'name', e)
            this.name1 = e
        },
        // 跟新节点名字
        updataNodeName() {
            const modeling = this.bpmnModeler.get('modeling')
            modeling.updateLabel(this.nodeId, this.name1)
        },
        changeEventType() { },
        newDiagram() {
            this.createNewDiagram(this.bpmnTemplate);
        },

        handlerRedo() {
            this.bpmnModeler.get("commandStack").redo();
        },
        handlerUndo() {
            this.bpmnModeler.get("commandStack").undo();
        },
        handlerZoom(radio) {
            const newScale = !radio ? 1.0 : this.scale + radio;
            this.bpmnModeler.get("canvas").zoom(newScale);
            this.scale = newScale;
        },

        async downloadBpmn() {
            try {
                const { xml } = await this.bpmnModeler.saveXML({ format: true });
                // 获取文件名
                const name = `${this.getFilename(xml)}.bpmn`;
                // 将文件名以及数据交给下载方法
                this.download({ name: name, data: xml });
            } catch (error) {
                this.toast.error('下载Bpmn失败，请重试')
            }
        },
        async downloadSvg() {
            try {
                const { xml } = await this.bpmnModeler.saveXML({ format: true });
                // 获取文件名
                const name = `${this.getFilename(xml)}.svg`;

                // 从建模器画布中提取svg图形标签
                let context = "";
                const djsGroupAll = this.$refs.canvas.querySelectorAll(".djs-group");
                for (let item of djsGroupAll) {
                    context += item.innerHTML;
                }
                // 获取svg的基本数据，长宽高
                const viewport = this.$refs.canvas
                    .querySelector(".viewport")
                    .getBBox();

                // 将标签和数据拼接成一个完整正常的svg图形
                const svg = `
            <svg
              xmlns="http://www.w3.org/2000/svg"
              xmlns:xlink="http://www.w3.org/1999/xlink"
              width="${viewport.width}"
              height="${viewport.height}"
              viewBox="${viewport.x} ${viewport.y} ${viewport.width} ${viewport.height}"
              version="1.1"
              >
              ${context}
            </svg>
          `;
                // 将文件名以及数据交给下载方法
                this.download({ name: name, data: svg });
            } catch (error) {
                this.toast.error('下载Svg失败，请重试')
            }
        },

        openBpmn(file) {
            const reader = new FileReader();
            // 读取File对象中的文本信息，编码格式为UTF-8
            reader.readAsText(file, "utf-8");
            reader.onload = () => {
                //读取完毕后将文本信息导入到Bpmn建模器
                this.createNewDiagram(reader.result);
            };
            return false;
        },

        getFilename(xml) {
            let start = xml.indexOf("process");
            let filename = xml.substr(start, xml.indexOf(">"));
            filename = filename.substr(filename.indexOf("id") + 4);
            filename = filename.substr(0, filename.indexOf('"'));
            return filename;
        },

        download({ name = "diagram.bpmn", data }) {
            // 这里就获取到了之前设置的隐藏链接
            const downloadLink = this.$refs.downloadLink;
            // 把输就转换为URI，下载要用到的
            const encodedData = encodeURIComponent(data);

            if (data) {
                // 将数据给到链接
                downloadLink.href =
                    "data:application/bpmn20-xml;charset=UTF-8," + encodedData;
                // 设置文件名
                downloadLink.download = name;
                // 触发点击事件开始下载
                downloadLink.click();
            }
        },
        // XML预览
        async perviewXML() {
            try {
                const { xml } = await this.bpmnModeler.saveXML({ format: true });
                this.perviewXMLStr = xml
                this.perviewXMLShow = true
            } catch (error) {
                this.toast.error('预览失败，请重试')
            }
        },
        // SVG预览
        async perviewSVG() {
            try {
                const { svg } = await this.bpmnModeler.saveSVG();
                this.perviewSVGData = svg
                this.perviewSVGShow = true
            } catch (error) {
                this.toast.error('预览失败，请重试')
            }
        },

        async init() {
            // 获取画布 element
            this.canvas = this.$refs.canvas;

            // 创建Bpmn对象
            this.bpmnModeler = new BpmnModeler({
                // 设置bpmn的绘图容器为上门获取的画布 element
                container: this.canvas,

                // 加入工具栏支持
                propertiesPanel: {
                    parent: "#js-properties-panel"
                },

                additionalModules: [propertiesProviderModule, customTranslateModule],
                moddleExtensions: {
                    camunda: camundaModdleDescriptor
                }
            });

            await this.createNewDiagram(this.value ? this.value : this.bpmnTemplate);
            // 监听画布点击事件，存储变化值
            var that = this
            this.$refs.canvas.addEventListener("click", async function () {
                try {
                    const { xml } = await that.bpmnModeler.saveXML({ format: true });
                    that.$emit("input", xml)
                    that.xmlData = xml
                } catch (error) {
                    that.$modal.msgError('实时保存失败')
                }
            })
            this.addEventBusListener()
        },
        async createNewDiagram(bpmn) {
            // 将字符串转换成图显示出来;
            try {
                const result = await this.bpmnModeler.importXML(bpmn);
            } catch (err) {
                this.$modal.msgError("打开模型出错,请确认该模型符合Bpmn2.0规范");
            }
        },

        // 监听
        addEventBusListener() {
            // 监听 element
            let that = this
            const eventBus = this.bpmnModeler.get('eventBus')
            const eventTypes = ['element.click', 'element.changed']
            eventTypes.forEach(function (eventType) {
                eventBus.on(eventType, function (e) {
                    console.log(e, 3333333)
                    const { element } = e

                    if (!e || e.element.type == 'bpmn:Process') return
                    if (eventType === 'element.changed') {
                        that.elementChanged(eventType, e)
                    } else if (eventType === 'element.click') {
                        console.log(e)
                        that.nodeId = element
                        if (e.element.type == 'bpmn:Task') {
                            that.nodeStatus = true
                            that.conditionStatus = false
                        } else if (e.element.type == 'bpmn:ExclusiveGateway') {
                            that.conditionStatus = true
                            that.nodeStatus = false
                        } else {
                            that.nodeStatus = false
                            that.conditionStatus = false
                        }
                        console.log('点击了element')
                    }
                })
            })
        },
        elementChanged(eventType, e) {
            // var shape = this.getShape(e.element.id)
            // console.log(shape, 22222222)
            // if (!shape) {
            //     if (shape.type) {
            //         // 若是shape为null则表示删除, 无论是shape还是connect删除都调用此处
            //         console.log('无效的shape')
            //         // 由于上面已经用 shape.removed 检测了shape的删除, 因此这里只判断是否是线
            //         if (this.isSequenceFlow(shape.type)) {
            //             console.log('删除了线')
            //         }
            //     }

            // }
            // if (shape.type) {
            //     if (!this.isInvalid(shape.type)) {
            //         if (this.isSequenceFlow(shape.type)) {
            //             console.log('改变了线')
            //         }
            //     }
            // }

        },
        isSequenceFlow(type) { // 判断是否是线
            return type === 'bpmn:SequenceFlow'
        },
        getShape(id) {
            var elementRegistry = this.bpmnModeler.get('elementRegistry')
            return elementRegistry.get(id)
        },
        isInvalid(param) { // 判断是否是无效的值
            return param === null || param === undefined || param === ''
        },
    },

};
</script>
  
<style lang="scss" >
.el-form-item--small .el-form-item__content {
    height: auto !important;
    ;
}

.rightMenu {
    margin-top: 20px;
    width: 300px;
    margin-right: 10px;
}

.container {
    display: flex;
}

.bpmn-canvas {
    width: 100%;
    height: 100vh;
    background: url('') repeat !important;
}

.action {
    position: fixed;
    bottom: 10px;
    left: 10px;
    display: flex;
}

.upload-demo {
    margin-right: 10px;
}

// 右菜单样式(注释隐藏菜单)
// .bpmn-js-properties-panel {
//   position: absolute;
//   top: 0;
//   right: 0px;
//   width: 300px;
//   max-height: 500px;
//   overflow-y: auto;
//   border: 1px solid rgba(0,0,0,0.1);
// }
.djs-palette.two-column.open {
    width: 50px;
}

.djs-palette {
    width: 55px;
}
</style>